#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QDesktopWidget>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QIODevice>
#include <QStandardPaths>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow), oldMousePos(0, 0) {
  ui->setupUi(this);
  //设置窗口位置
  this->readConfigInfo();
  this->setWindowFlags(Qt::FramelessWindowHint    //去边框
                       | Qt::WindowStaysOnTopHint //最低层显示
                       | Qt::Tool                 //不在任务栏显示
                       );
  this->setAttribute(Qt::WA_TranslucentBackground, true);
  this->SetSystemTray();
  process = new QProcess(this);
  timer = new QTimer(this);
  timer->connect(timer, SIGNAL(timeout()), this, SLOT(GetInformation()));
  timer->start(1000);
}

void MainWindow::mousePressEvent(QMouseEvent *event) {
  if (!isMousePressed && event->button() == Qt::LeftButton) {
    isMousePressed = true;
    oldMousePos = event->globalPos() - this->pos();
    this->setCursor(Qt::ClosedHandCursor);
  }
}

void MainWindow::mouseMoveEvent(QMouseEvent *event) {
  if (isMousePressed) {
    this->move(event->globalPos() - oldMousePos);
    event->accept();
  }
}

void MainWindow::mouseReleaseEvent(QMouseEvent *event) {
  if (isMousePressed && event->button() == Qt::LeftButton) {
    int x = this->x();
    int y = this->y();
    if (this->pos().x() < 0) {
      x = 0;
    } else if (QApplication::desktop()->width() - x < this->width()) {
      x = QApplication::desktop()->width() - this->width();
    }
    if (this->pos().y() < 0) {
      y = 0;
    } else if (QApplication::desktop()->height() - y < this->height()) {
      y = QApplication::desktop()->height() - this->height();
    }
    this->move(x, y);
    isMousePressed = false;
    setCursor(Qt::ArrowCursor);
    event->accept();
  }
}

void MainWindow::closeEvent(QCloseEvent *event) {
  this->writeConfigInfo();
  event->accept();
  QApplication::exit();
}

void MainWindow::writeConfigInfo() {
  QFile configFile(
      QStandardPaths::standardLocations(QStandardPaths::HomeLocation).front() +
      "/.NetWatcher/config.ini");
  if (configFile.open(QIODevice::WriteOnly)) {
    configFile.reset();
    QString posiMsg = "px=" + QString().setNum(this->pos().x()) + "," + "py=" +
                      QString().setNum(this->pos().y());
    configFile.write(posiMsg.toUtf8());
    configFile.flush();
    configFile.close();
  }
}

void MainWindow::readConfigInfo() {
  QFile configFile(
      QStandardPaths::standardLocations(QStandardPaths::HomeLocation).front() +
      "/.NetWatcher/config.ini");
  //创建父目录
  QDir dir = QFileInfo(configFile).dir();
  dir.cd("../");
  dir.mkdir(".NetWatcher");
  //写入配置数据
  if (configFile.exists()) {
    if (configFile.open(QIODevice::ReadOnly)) {
      QString data = configFile.readAll();
      configFile.close();
      QStringList datas = data.split(",");
      if (!datas.isEmpty()) {
        bool isOk = false;
        int x = datas.at(0).split("=").at(1).toInt(&isOk, 0);
        int y = datas.at(1).split("=").at(1).toInt(&isOk, 0);
        this->move(x, y);
        return;
      }
    }
  } else {
    this->move(QApplication::desktop()->width() - 120,
               QApplication::desktop()->height() - 80);
  }
}

void MainWindow::OnTrayContextMenuClick(QAction *action) {
  switch (action->data().toInt()) {
  case MENU_ITEM_OPEN_MONITOR:
    this->OpenGnomeSystemMonitor();
    break;
  case MENU_ITEM_EXIT_APPLICATION:
    timer->stop();
    if (process->isOpen()) {
      process->close();
    }
    this->close();
    break;
  }
}

//读取文件并转换为字符串
QString MainWindow::ReadFile2String(QString filePath) {
  QFile file(filePath);
  if (file.open(QIODevice::ReadOnly)) {
    QString cssContent(file.readAll());
    file.close();
    return cssContent;
  }
  return NULL;
}

//获取信息
void MainWindow::GetInformation() {
  timer->stop();
  GetNetInformation();
  GetFreeMemoryInfo();
  timer->start(1000);
}

//获取网络流量信息
void MainWindow::GetNetInformation() {
  uploadCount = 0;
  downloadCount = 0;
  process->start("ip -s link");
  if (process->waitForStarted(2000) && process->waitForFinished(1000)) {
    QByteArray infoBytes = process->readAllStandardOutput();
    if (!infoBytes.isEmpty()) {
      QString infoResult(infoBytes);
      //计算上传流量
      QRegularExpression regExpress("collsns[\\s\\S]+?\\d+");
      QRegularExpressionMatchIterator matcherIter =
          regExpress.globalMatch(infoResult);
      while (matcherIter.hasNext()) {
        QString net = matcherIter.next().captured(0);
        net.remove(QRegularExpression("[\\s\\S]+ "));
        uploadCount += net.toInt();
      }
      qint64 tmp = uploadCount - oldUploadCount;
      if (oldUploadCount != 0)
        ui->lbUpload->setText("⇧" + GetSizeInfo(tmp));
      oldUploadCount = uploadCount;
      //计算下载流量
      regExpress.setPattern("mcast[\\s\\S]+?\\d+");
      matcherIter = regExpress.globalMatch(infoResult);
      while (matcherIter.hasNext()) {
        QString net = matcherIter.next().captured(0);
        net.remove(QRegularExpression("[\\s\\S]+ "));
        downloadCount += net.toLongLong();
      }
      tmp = downloadCount - oldDownloadCount;
      if (oldDownloadCount != 0)
        ui->lbDownload->setText("⇩" + GetSizeInfo(tmp));
      oldDownloadCount = downloadCount;
    }
  }
}

//获取内存信息
void MainWindow::GetFreeMemoryInfo() {
  process->start("free -m");
  if (process->waitForStarted(2000) && process->waitForFinished(1000)) {
    QByteArray infoResult = process->readAllStandardOutput();
    if (!infoResult.isEmpty()) {
      QRegularExpression regExpress("\\d+.+");
      QString value = regExpress.match(infoResult).captured(0);
      QStringList infoList = value.split(QRegExp(" +"));
      QString totalStr = infoList.at(0), availableStr = infoList.at(5);
      qint64 totalCount = totalStr.toLongLong(),
             availableCount = availableStr.toLongLong();
      qint64 used = totalCount - availableCount;
      int usedPercent = qIntCast(used * 100.0 / totalCount);
      if (usedPercent >= 90)
        ui->pbMemory->setStyleSheet(ReadFile2String(":/memory_danger.css"));
      else if (usedPercent >= 60)
        ui->pbMemory->setStyleSheet(ReadFile2String(":/memory_waring.css"));
      else
        ui->pbMemory->setStyleSheet(ReadFile2String(":/memory_normal.css"));
      ui->pbMemory->setValue(usedPercent);
    }
  }
}

//重新处理文件大小信息
void MainWindow::ReDealSizeInfo(QString *result) {
  QRegExp reg("^\\d+[.]0$");
  if (reg.exactMatch(*result))
    result = &result->replace(".0", "");
}

//计算文件大小信息
QString MainWindow::GetSizeInfo(qint64 value) {
  if (value >= 1024 * 1024) {
    QString result = QString::number(value / 1024.0 / 1024.0, 'd', 1);
    ReDealSizeInfo(&result);
    return result + "M/s";
  } else if (value >= 1024) {

    if (value / 1024 > 999) {
      QString result = QString::number(value / 1024.0 / 1024.0, 'd', 1);
      ReDealSizeInfo(&result);
      return result + "M/s";
    }
    QString result = QString::number(value / 1024.0, 'd', 1);
    ReDealSizeInfo(&result);
    return result + "K/s";
  } else {
    if (value / 1024 > 999) {
      QString result = QString::number(value / 1024.0, 'd', 1);
      ReDealSizeInfo(&result);
      return result + "K/s";
    }
    return QString().setNum(value) + "B/s";
  }
}

void MainWindow::OpenGnomeSystemMonitor() {
  process->start("gnome-system-monitor");
  if (process->waitForStarted(2000) && process->waitForFinished(1000)) {
    if (process->error() != QProcess::ProcessError::FailedToStart) {
      //启动成功
      return;
    }
  }
}

void MainWindow::SetSystemTray() {
  trayIcon = new QSystemTrayIcon(QIcon(":/icon.png"), this);
  trayIcon->setToolTip(tr("流量监控悬浮框"));
  QMenu *menu = new QMenu();
  QAction *monitorAction = new QAction(tr("任务管理"));
  monitorAction->setData(QVariant(MENU_ITEM_OPEN_MONITOR));
  menu->addAction(monitorAction);
  QObject::connect(menu, SIGNAL(triggered(QAction *)), this,
                   SLOT(OnTrayContextMenuClick(QAction *)));
  QAction *exitAction = new QAction(tr("退出应用"));
  exitAction->setData(QVariant(MENU_ITEM_EXIT_APPLICATION));
  menu->addAction(exitAction);
  QObject::connect(menu, SIGNAL(triggered(QAction *)), this,
                   SLOT(OnTrayContextMenuClick(QAction *)));
  trayIcon->setContextMenu(menu);
  //    QObject::connect(trayIcon,
  //    SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this,
  //    SLOT(OnActiveSystemTrayIcon()));
  trayIcon->show();
}

MainWindow::~MainWindow() { delete ui; }
